iT邦幫忙

2023 iThome 鐵人賽

DAY 3
0
自我挑戰組

React Native 奇幻之旅系列 第 3

【DAY3】RN內建組件(2)-Touchables*

  • 分享至 

  • xImage
  •  

React Native 內建的點擊類組件(統稱為Touchables*)有以下幾種:

  • TouchableHighlight
  • TouchableOpacity
  • TouchableWithoutFeedback
  • TouchableNativeFeedback
  • Button
  • Pressable

雖然點擊類的組件有這麼多個,但官方建議在未來改為使用 Pressable,因為 Pressable 涵蓋了所有 Touchables* 的功能。

Touchables* 和 Pressable 的差異

  1. TouchableWithoutFeedbackPressable 預設點擊是沒有回饋效果的。
TouchableOpacity TouchableHighlight TouchableNativeFeedback
點擊時會變透明 點擊時會變色(underlayColor) 點擊時會有波紋效果(僅限 Android)
TouchableWithoutFeedback Pressable
預設點擊沒有回饋效果 預設點擊沒有回饋效果
  1. Pressable 可以自定義點擊交互效果(包括單擊、長按...等),Touchables* 是各司其職

  2. TouchableNativeFeedback, TouchableWithoutFeedback 本身是沒有辦法設置樣式的,因為它們是用來處理點擊時的反饋效果的。

    import React from "react"
    import { StyleSheet, Text, TouchableOpacity, TouchableHighlight, TouchableNativeFeedback, TouchableWithoutFeedback, Pressable } from "react-native"
    
    const App = () => {
      return (
        <>
          {/* TouchableOpacity */}
          <TouchableOpacity style={styles.button} onPress={() => console.log('TouchableOpacity')}>
            <Text>TouchableOpacity</Text>
          </TouchableOpacity>
    
          {/* TouchableHighlight */}
          <TouchableHighlight style={styles.button} onPress={() => console.log('TouchableHighlight')}>
            <Text>TouchableHighlight</Text>
          </TouchableHighlight>
    
          {/* TouchableNativeFeedback */}
          <TouchableNativeFeedback style={styles.button} onPress={() => console.log('TouchableNativeFeedback')}>
            <Text>TouchableNativeFeedback</Text>
          </TouchableNativeFeedback>
    
          {/* TouchableWithoutFeedback */}
          <TouchableWithoutFeedback style={styles.button} onPress={() => console.log('TouchableWithoutFeedback')}>
            <Text>TouchableWithoutFeedback</Text>
          </TouchableWithoutFeedback>
    
          {/* Pressable */}
          <Pressable style={styles.button} onPress={() => console.log('Pressable')}>
            <Text>Pressable</Text>
          </Pressable>
        </>
      )
    }
    
    export default App
    
    const styles = StyleSheet.create({
      button: {
        padding: 10,
        backgroundColor: 'white',
        borderRadius: 4,
        marginVertical: 10
      }
    })
    

    需要使用 View

    <>
        {/* TouchableNativeFeedback */}
        <TouchableNativeFeedback onPress={() => console.log('TouchableNativeFeedback')}>
            <View style={styles.button}>
              <Text>TouchableNativeFeedback</Text>
            </View>
        </TouchableNativeFeedback>
    
        {/* TouchableWithoutFeedback */}
        <TouchableWithoutFeedback onPress={() => console.log('TouchableWithoutFeedback')}>
            <View style={styles.button}>
              <Text>TouchableWithoutFeedback</Text>
            </View>
        </TouchableWithoutFeedback>
    </>
    

Pressable 實現所有 Touchables*

TouchableWithoutFeedback

不需要做任何設置,因為 Pressable 本身也沒有點擊回饋效果。

TouchableOpacity

Pressable 的 style 有一個 pressed 的屬性,用於判斷是否被點擊,當點擊時改變透明度即可達到 TouchableOpacity 的效果。

<Pressable
    style={({ pressed }) => [
      styles.button,
      { opacity: pressed ? 0.5 : 1 }
    ]}
    onPress={() => console.log('Pressable')}
>
    <Text>Pressable</Text>
</Pressable>

TouchableHighlight

TouchableOpacity 實現方式一樣

<Pressable
    style={({ pressed }) => [
      styles.button,
      { backgroundColor: pressed ? 'skyblue' : 'white' }
    ]}
    onPress={() => console.log('Pressable')}
>
    <Text>Pressable</Text>
</Pressable>

TouchableNativeFeedback

設置 android_ripple prop,包含以下屬性:

NAME TYPE REQUIRED DESCRIPTION
color color No 定義波紋的顏色
borderless boolean No 定義波紋效果是否包含邊框
radius number No 定義波紋的半徑
<Pressable
    android_ripple={{
      color: '#ddd',
      borderless: true,
    }}
    style={styles.button}
    onPress={() => console.log('Pressable')}
>
    <Text>Pressable</Text>
</Pressable>

Pressable 點擊動畫

需要搭配 React Native 內置的 Animated API,這邊簡單做一個點擊時放大、釋放時縮小的效果:

import React, { useRef } from "react"
import { StyleSheet, Text, Animated, Pressable, View } from "react-native"

export const TouchablesPage = () => {
  const scaleValue = useRef(new Animated.Value(1)).current

  const handlePressIn = () => {
    Animated.spring(scaleValue, {
      toValue: 1.2,
      useNativeDriver: false,
    }).start()
  }

  const handlePressOut = () => {
    Animated.spring(scaleValue, {
      toValue: 1,
      useNativeDriver: false,
    }).start()
  }

  return (
      <Pressable
        onPressIn={handlePressIn}
        onPressOut={handlePressOut}
      >
        <Animated.View
          style={[styles.button, {
            transform: [{ scale: scaleValue }],
          }]}
        >
          <Text>Pressable</Text>
        </Animated.View>
      </Pressable>
  )
}

const styles = StyleSheet.create({
  button: {
    padding: 10,
    backgroundColor: 'white',
    borderRadius: 4,
    marginVertical: 10
  }
})

總結

根據需求選擇使用 PressableTouchables* 哪種即可,沒有特別需求的話就用 Pressable 方便後續修改點擊回饋或者在點擊時做一些處理,但是有些特殊情況也會需要用到 TouchableWithoutFeedback ,比如可以用在點擊背景關閉Modal(onBackdropPress),這個等說到 Modal 會再提。

參考資料



附贈昨天抓到的異色小火龍+亂入的原色小火龍XD


上一篇
【DAY2】RN內建組件(1)-TextInput
下一篇
【DAY4】RN內建組件(3)-Modal
系列文
React Native 奇幻之旅31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言